#include "Actor3D.hpp"
#include <QxtLogger>
#include <exception>

Actor3D::Actor3D(): v_data(0),v_colors(0),v_normals(0),vboDataId(0),vboNormalId(0),vboColorId(0)
{
    // set up the
    dims << "x" << "y" << "z";
    derivs << "static" << "velocity" << "acceleration";
    scales << "position" << "rotation" << "scale";
    values.insert("null",0.0f);
}

//
void Actor3D::load() {
    // loads the data into the vbuffer object
    if(v_data and v_data->length()==0) {
        qxtLog->warning() << "This actor has no data";
        return;
    }
    if(v_data) {
        void * data = v_data->data();
        glGenBuffers(1,&vboDataId);
        glBindBuffer(GL_ARRAY_BUFFER_ARB,vboDataId);
        glBufferData(GL_ARRAY_BUFFER_ARB,v_data->length()*3,data,GL_STATIC_DRAW_ARB);
        delete[] data;
        delete v_data;
        v_data = 0;
    }
    if(v_colors) {
        void * data = v_colors->data();
        glGenBuffers(1,&vboDataId);
        glBindBuffer(GL_ARRAY_BUFFER_ARB,vboColorId);
        glBufferData(GL_ARRAY_BUFFER_ARB,v_colors->length()*3,data,GL_STATIC_DRAW_ARB);
        delete[] data;
        delete v_colors;
        v_data = 0;
    }
    if(v_normals) {
        void * data = v_normals->data();
        glGenBuffers(1,&vboDataId);
        glBindBuffer(GL_ARRAY_BUFFER_ARB,vboNormalId);
        glBufferData(GL_ARRAY_BUFFER_ARB,v_normals->length()*3,data,GL_STATIC_DRAW_ARB);
        delete[] data;
        delete v_normals;
        v_data = 0;
    }

}

void Actor3D::update(float dt) {
    // foreach dimension
    foreach(QByteArray dim, dims){
        foreach(QByteArray scale, scales) {
            getF(dim+"-"+scale+"-velocity") += dt*getF(dim+"-"+scale+"-acceleration");
            getF(dim+"-"+scale+"-static") += dt*getF(dim+"-"+scale+"-velocity");
        }
    }
}

bool Actor3D::keyValid(const QByteArray &key) {
    static QList<QByteArray> valids;
    // format dimension-derivitave-scalar
    // eg x-static-position
    //    y-velocity-rotation
    //    z-acceleration-scale
    if(valids.empty()) {
        // positions
        QList<QByteArray> dim;
        dim << "x" << "y" << "z";
        QList<QByteArray> der;
        der << "static" << "velocity" << "acceleration";
        QList<QByteArray> sca;
        sca << "position" << "rotation" << "scale";
        foreach(QByteArray a, dim)
            foreach(QByteArray b, sca)
                foreach(QByteArray c, der)
                    valids << a+"-"+b+"-"+c;
    }
    return valids.contains(key);
}
float Actor3D::getF(const QByteArray &key) const {
    if(keyValid(key)){
        if(values.contains(key)) return values.value(key);
        else if ( key.startsWith("sca") || key.at(2)=='a') return 1.0f;
        else return 0.0f;
    } else {
        return 0.0f;
    }
}

float& Actor3D::getF(const QByteArray &key) {
    if(keyValid(key)){
        if(!values.contains(key)) values[key]=0.0f;
        else if ( key.startsWith("sca") || key.at(2)=='a') values[key]=1.0f;
        return values[key];
    } else {
        throw new std::exception();
    }
}
